package com.ktjy.ktmall.servlet;

import cn.hutool.core.lang.id.NanoId;
import cn.hutool.http.*;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ktjy.ktmall.entity.AjaxResult;
import com.ktjy.ktmall.entity.WeChatPhoneInfo;
import com.ktjy.ktmall.entity.WxUser;
import com.ktjy.ktmall.service.WxUserService;
import com.ktjy.ktmall.service.impl.WxUserServiceImpl;
import com.mysql.cj.util.StringUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.*;

// 手机号一键登录
@WebServlet(name = "PhoneLoginServlet", urlPatterns = "/uni/phoneLogin")
public class PhoneLoginServlet extends HttpServlet {

    private String appId = null;   //小程序ID(appId)
    private String secret = null; // 小程序密钥
    private String accessTokenhttps = null; // 得到获取用户基本信息所需要的token网址
    private String webAccessTokenhttps = null; // 用于获取openId开发者id
    WxUserService wxUserService = null;

    // 微信支付的相关配置参数
    public void getConfigParam() {
        Properties params = new Properties();
        String configFile = "wxpay.properties";//配置文件路径
        //加载配置文件到输入流中
        InputStream is= PhoneLoginServlet.class.getClassLoader().getResourceAsStream(configFile);

        try {
            //从输入流中读取属性列表
            params.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //根据指定的获取对应的值
        appId = params.getProperty("wx.appId");
        secret = params.getProperty("wx.secret");
        accessTokenhttps = params.getProperty("wx.accessTokenhttps");
        webAccessTokenhttps = params.getProperty("wx.webAccessTokenhttps");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        getConfigParam();
        wxUserService = new WxUserServiceImpl();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        // 手机号获取凭证
        String code = request.getParameter("code");
        // 小程序调用wx.login()获取到的code值，临时登录凭证
        String loginCode = request.getParameter("loginCode");
        AjaxResult result = null;
        if (StringUtils.isNullOrEmpty(code)) {
            result = AjaxResult.error("手机号获取凭证不能为空！");
            out.print(JSONArray.toJSONString(result));
            return;
        }
        /**
         * 获取接口调用凭据
         * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
         */
        String url1 = String.format(accessTokenhttps,appId, secret);
        String resp = HttpUtil.get(url1);
        // JSONObject导的包是：com.alibaba.fastjson.JSONObject
        JSONObject jsonObject = JSONObject.parseObject(resp);
        String accessToken = jsonObject.getString("access_token");
        if (jsonObject.getString("errcode") != null) {
            result = AjaxResult.error("手机号授权失败", jsonObject.getString("errmsg"));
            out.print(JSONArray.toJSONString(result));
            return;
        }

        //通过accessToken和code来获取用户手机号
        String phoneNumber = getPhoneNumber(code, accessToken);
        if (phoneNumber == null) {
            out.print(JSON.toJSONString(AjaxResult.error("手机号获取失败", jsonObject.getString("errmsg"))));
            return;
        }
        // 获取开发者id
        String openId = getOpenId(loginCode);
        if (StringUtils.isNullOrEmpty(openId)) {
            out.print(JSON.toJSONString(AjaxResult.error("openId获取失败")));
            return;
        }

        WxUser wxUser = wxUserService.findByMobile(phoneNumber);
        if (null == wxUser) {// 注册
            wxUser = new WxUser();
            wxUser.setUsername("科泰购用户" + NanoId.randomNanoId(6)); //获取随机字符串
            wxUser.setOpenId(openId); // 开发者id
            wxUser.setPassword("123456");
            wxUser.setLastLoginIp("0:0:0:0:0:0:0:1");
            wxUser.setMobile(phoneNumber); // 手机号
            wxUser.setLastLoginTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
            wxUser.setAvatar("https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0");
            wxUser.setNickname("科泰购昵称" + NanoId.randomNanoId(6));

            wxUserService.insert(wxUser); //新增(注册)
        } else {
            wxUser.setLastLoginTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
            wxUserService.updateLastLoginTime(wxUser.getId()); // 修改最近一次登录时间
        }
        // 使用Hutool工具类生成token令牌
        wxUser.setToken("Wx" + NanoId.randomNanoId(16));
        result = AjaxResult.success("登录成功", wxUser);
        out.print(JSONArray.toJSONString(result));
        out.flush();
        out.close();
    }


    /**
     * 请求微信接口服务，用code换取用户手机号（每个code只能使用一次，code的有效期为5min）
     * https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/phonenumber/phonenumber.getPhoneNumber.html
     * 响应体的返回数据结构如下：
     * {
     *     "errcode":0,
     *     "errmsg":"ok",
     *     "phone_info": {
     *         "phoneNumber":"xxxxxx",
     *         "purePhoneNumber": "xxxxxx",
     *         "countryCode": 86,
     *         "watermark": {
     *             "timestamp": 1637744274,
     *             "appid": "xxxx"
     *         }
     *     }
     * }
     * @param code 手机号获取凭证
     * @param accessToken 获取接口调用凭据
     * @return 返回获取到的手机号码
     */
    public static String getPhoneNumber(String code, String accessToken) {
        String phoneNumber = null;  // 用来保存获取到的手机号码
        try {
            // 接口调用凭证：accessToken
            String baseUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
            HashMap<String, Object> requestParam = new HashMap<>();
            // 手机号调用凭证
            requestParam.put("code", code);
            // 发送post请求读取调用微信接口获取openid用户唯一标识
            String jsonStr = JSONUtil.toJsonStr(requestParam);
            HttpResponse response = HttpRequest.post(baseUrl)
                    .header(Header.CONTENT_ENCODING, "UTF-8")
                    .timeout(60 * 1000) // 设置超时时间
                    // 发送json数据需要设置contentType
                    .header(Header.CONTENT_TYPE, "application/x-www-form-urlencoded")
                    .body(jsonStr)
                    .execute();
            // 得到响应体对象
            String body = response.body();
            // 将body字符串类型转换成JSON对象
            cn.hutool.json.JSONObject object = JSONUtil.parseObj(body);
            // 获取key为phone_info的数据，再转换成WeChatPhone对象(此类是需要临时创建)
            WeChatPhoneInfo phoneInfo = object.get("phone_info", WeChatPhoneInfo.class);
            phoneNumber = phoneInfo.getPhoneNumber();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return phoneNumber; // 返回获取到的手机号码
    }

    /**
     * 获取OpenId开发者id
     * @param code 登录临时凭证
     * @return
     */
    public String getOpenId(String code) {
        String url = String.format(webAccessTokenhttps,appId, secret,code);
        // HttpUtil.get()是发送get请求，请求上面的获取接口调用凭据的API
        String resp = HttpUtil.get(url);
        // JSONObject导的包是：com.alibaba.fastjson.JSONObject
        JSONObject jsonObject = JSONObject.parseObject(resp);
        String openid = jsonObject.getString("openid");
        return openid;
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

}
